﻿#ifndef PAGE_HPP
#define PAGE_HPP

#include "typedef.hpp"
#include <array>
#include <unordered_map>

class PTE
{
public:
	uint8_t meta;
	uint64_t pfn; // Physical Page Frame Number
	PTE() = default;
	PTE(uint64_t src) : meta((src >> 4) & 0xff), pfn(src >> 12) {}
	~PTE() = default;
	operator uint64_t() { return ((uint64_t)(meta) << 4) | (pfn << 12); }
};

using Item = std::pair<PTE, uint64_t>; // PTE and its source
using PageList = std::pair<uint64_t, Item>;

template <int N>
class PageBlock
{
private:
	std::list<PageList> lines;
	std::unordered_map<uint64_t, std::list<PageList>::iterator> idx;

public:
	PageBlock() = default;
	~PageBlock() = default;
	PageList *get(uint64_t);
	void put(uint64_t, PageList);
	void remove(uint64_t);
	void clear();
};

class MMU
{
private:
	std::map<uint8_t, PageBlock<16>> l1i_4k, l1i_2m;
	std::map<uint8_t, PageBlock<16>> l1d_4k, l1d_2m, l1d_1g;
	std::map<uint8_t, PageBlock<8>> l2_4k, l2_2m, l2_1g;
	PageList *InsSearch(uint64_t);
	PageList *DataSearch(uint64_t);

public:
	std::pair<uint64_t *, uint64_t *> RvReg;
	std::pair<bool, uint8_t> tlbMeta; //{need swap?,page size}
	MMU() = default;
	~MMU() = default;
	std::pair<bool, uint64_t> operator()(uint64_t *, uint8_t, uint64_t, uint64_t *);
	std::pair<bool, uint64_t> update(uint64_t *, uint8_t, uint64_t, uint64_t *);
	void flush();
};

#endif